package org.formatter.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;

import org.formatter.common.DomUtil;
import org.formatter.common.FormatException;
import org.formatter.rule.Rule;
import org.formatter.rule.SimpleTextRule;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Formatter {
	public static void format(InputStream in, OutputStream out, int blocklength, List<Rule> rules) throws FormatException {
		StringBuffer buffer = new StringBuffer();
		try {
			for (int i; (i = in.read()) != -1;) {
				buffer.append((char) i);
				if (buffer.length() > blocklength) {
					for (Rule rule : rules) {
						String tail = buffer.substring(blocklength);
						buffer.delete(blocklength, buffer.length());
						tail = rule.format(tail);
						buffer.append(tail);
					}
				}
				while (buffer.length() > blocklength) {
					int j = buffer.charAt(0);
					buffer.deleteCharAt(0);
					out.write(j);
				}
			}
			out.write(buffer.toString().getBytes());
		} catch (IOException e) {
			throw new FormatException("",e);
		}
	}

	public static void format(InputStream in, OutputStream out,
			Document rulesDoc) throws FormatException {
		List<Rule> rules = new ArrayList<Rule>();
		Element rootEle = rulesDoc.getDocumentElement();
		Element blocklengthEle = DomUtil.getFirstChildElement(rootEle,
				"blocklength");
		int blocklength = Integer
				.parseInt(DomUtil.getChildText(blocklengthEle));

		Element rulesEle = DomUtil.getFirstChildElement(rootEle,
				"rules");
		NodeList nodeList = rulesEle.getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node node = nodeList.item(i);
			if ("simpletextrule".equals(node.getNodeName())) {
				SimpleTextRule rule = new SimpleTextRule();
				Element beforechipEle = DomUtil.getFirstChildElement(node, "beforechip");
				if(null!=beforechipEle){
					String beforechip = DomUtil.getChildText(beforechipEle);
					beforechip = readparams(beforechip);
					rule.setBeforechip(beforechip);
				}
				
				Element chipEle = DomUtil.getFirstChildElement(node, "chip");
				if(null!=chipEle){
					String chip = DomUtil.getChildText(chipEle);
					chip = readparams(chip);
					rule.setChip(chip);
				}
				
				Element replacechipEle = DomUtil.getFirstChildElement(node, "replacechip");
				if(null!=replacechipEle){
					String replacechip = DomUtil.getChildText(replacechipEle);
					replacechip= readparams(replacechip);
					rule.setReplacechip(replacechip);
				}
				
				Element afterchipEle = DomUtil.getFirstChildElement(node, "afterchip");
				if(null!=afterchipEle){
					String afterchip = DomUtil.getChildText(afterchipEle);
					afterchip= readparams(afterchip);
					rule.setAfterchip(afterchip);
				}
				rules.add(rule);
			}
		}
		format(in,out,blocklength,rules);
	}

	private static String readparams(String input) {
		Matcher matcher = Pattern.compile("\\$\\{([^{}]*)\\}[.]*").matcher(input);
		while (matcher.find()) {
			String propkey = matcher.group(1);
			String prop = System.getProperty(propkey);
			input = input.replace("${" + propkey + "}", prop);
		}
		return input;
	}

	public static void main(String[] args) throws FormatException {
		Document document;
		InputStream docin = null;
		try {
			docin = Formatter.class.getClassLoader().getResourceAsStream(
					"jsformatter.xml");
			document = DomUtil.read2Doc(docin);
		} catch (ParserConfigurationException e) {
			throw new FormatException("", e);
		} catch (SAXException e) {
			throw new FormatException("", e);
		} catch (IOException e) {
			throw new FormatException("", e);
		} finally {
			if (null != docin) {
				try {
					docin.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
				}
			}
		}

		OutputStream out = System.out;
		InputStream in = Formatter.class.getClassLoader().getResourceAsStream(
				"dojo.js");

		format(in, out, document);
	}
}
